package excel

import (
	"context"
	"github.com/gogf/gf/v2/errors/gerror"
	"reflect"
	"strings"

	"github.com/gogf/gf/v2/frame/g"
	"github.com/gogf/gf/v2/net/ghttp"
	"github.com/xuri/excelize/v2"
)

type (
	// ExporterOption 导出器选项
	ExporterOption func(*GenericExporter)

	// GenericExporter 通用Excel导出器
	GenericExporter struct {
		fileName   string
		data       interface{}
		headerMap  map[string]string // 字段名->表头映射
		formatters map[string]func(interface{}) interface{}
		fields     []string // 要导出的字段列表
	}
)

// NewGenericExporter 创建通用导出器
func NewGenericExporter(
	fileName string,
	data interface{},
	opts ...ExporterOption,
) *GenericExporter {
	exporter := &GenericExporter{
		fileName:   fileName,
		data:       data,
		headerMap:  make(map[string]string),
		formatters: make(map[string]func(interface{}) interface{}),
		fields:     make([]string, 0),
	}

	for _, opt := range opts {
		opt(exporter)
	}

	// 如果指定了headerMap但未指定fields，则使用headerMap的key作为fields
	if len(exporter.fields) == 0 && len(exporter.headerMap) > 0 {
		for field := range exporter.headerMap {
			exporter.fields = append(exporter.fields, field)
		}
	}

	return exporter
}

// WithHeaderMap 设置表头映射
func WithHeaderMap(m map[string]string) ExporterOption {
	return func(e *GenericExporter) {
		for k, v := range m {
			e.headerMap[k] = v
		}
	}
}

// WithFields 显式指定要导出的字段
func WithFields(fields ...string) ExporterOption {
	return func(e *GenericExporter) {
		e.fields = fields
	}
}

// WithFormatter 设置字段格式化函数
func WithFormatter(field string, formatter func(interface{}) interface{}) ExporterOption {
	return func(e *GenericExporter) {
		e.formatters[field] = formatter
	}
}

// Export 执行导出
func (e *GenericExporter) Export(ctx context.Context, response *ghttp.Response) error {
	f := excelize.NewFile()
	defer func() {
		if err := f.Close(); err != nil {
			g.Log().Error(ctx, err)
		}
	}()

	sheetName := "Sheet1"
	index, _ := f.NewSheet(sheetName)
	f.SetActiveSheet(index)
	f.DeleteSheet("Sheet1")

	// 处理数据
	value := reflect.ValueOf(e.data)
	if value.Kind() != reflect.Slice {
		return gerror.New("导出数据必须是切片类型")
	}

	// 获取表头
	headers := e.getHeaders()
	for col, header := range headers {
		cell, _ := excelize.CoordinatesToCellName(col+1, 1)
		f.SetCellValue(sheetName, cell, header)
	}

	// 填充数据
	for row := 0; row < value.Len(); row++ {
		item := value.Index(row).Interface()
		for col, field := range e.fields {
			cell, _ := excelize.CoordinatesToCellName(col+1, row+2)
			fieldValue := e.getFieldValue(item, field)
			f.SetCellValue(sheetName, cell, fieldValue)
		}
	}

	// 设置响应头
	response.Header().Set("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
	response.Header().Set("Content-Disposition", "attachment; filename="+e.fileName)
	response.Header().Set("Content-Transfer-Encoding", "binary")

	// 写入响应
	return f.Write(response.Writer)
}

// getHeaders 获取表头
func (e *GenericExporter) getHeaders() []string {
	var headers []string
	for _, field := range e.fields {
		if header, ok := e.headerMap[field]; ok {
			headers = append(headers, header)
		} else {
			headers = append(headers, field)
		}
	}
	return headers
}

// getFieldValue 获取字段值（应用格式化）
func (e *GenericExporter) getFieldValue(item interface{}, field string) interface{} {
	v := reflect.ValueOf(item)
	if v.Kind() == reflect.Ptr {
		v = v.Elem()
	}

	// 支持嵌套字段 (如 "User.Name")
	fieldParts := strings.Split(field, ".")
	for _, part := range fieldParts {
		if v.Kind() == reflect.Ptr {
			v = v.Elem()
		}
		v = v.FieldByName(part)
		if !v.IsValid() {
			return ""
		}
	}

	fieldValue := v.Interface()

	// 应用格式化函数
	if formatter, ok := e.formatters[field]; ok {
		return formatter(fieldValue)
	}

	return fieldValue
}
